package com.ywu.boot.spiInterceptor;

import com.ywu.boot.config.BootConfigAppConfig;
import com.ywu.boot.context.YwuContext;
import com.ywu.boot.context.YwuContextHolder;
import com.ywu.boot.exception.YwuRuntimeException;
import com.ywu.common.gson.GsonUtils;
import com.ywu.common.utils.AesUtils;
import feign.RequestInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.UUID;

/**
 * @ClassName RequestConfiguration
 * @Description TODO
 * @Author GroundDemo
 * @Date 2024/3/16 13:59
 * @Version 1.0
 **/
@Configuration
@Slf4j
public class RequestInterceptorConfiguration {
    private static final String YWU_CONTEXT_HEADER = "YWU-CONTEXT-HEADER";

    @Autowired
    private BootConfigAppConfig bootConfigAppConfig;

    /**
    * @Author GroundDemo
    * @Description feign在远程调用之前会执行所有的RequestInterceptor拦截器
    * @Date 13:59 2024/3/16
    * @Param []
    * @return RequestInterceptor
    **/
    @Bean("requestInterceptor")
    public RequestInterceptor requestInterceptor(BootConfigAppConfig appConfig) {
        return requestTemplate -> {
            // 1、将上下文对象序列化到请求头中
            YwuContext currentContext = YwuContextHolder.getCurrentContext();
            // 序列化数据
            String currentContextStr = GsonUtils.serialize(currentContext);
            String encrypt;
            try {
                encrypt = AesUtils.encrypt(currentContextStr, bootConfigAppConfig.getSecretKey());
            } catch (Exception e) {
                log.error("handleUserRole error {}", e.getMessage());
                throw new YwuRuntimeException(e.getMessage());
            }
            requestTemplate.header(YWU_CONTEXT_HEADER, encrypt);
            // 设置SPI下的spanId
            requestTemplate.header("X-Pix-Ywu-Span-Id", UUID.randomUUID().toString().replace("-", ""));
            // 2、使用 RequestContextHolder 拿到请求数据，RequestContextHolder底层使用过线程共享数据 ThreadLocal<RequestAttributes>
            // 通过拿取到的当前线程的请求头往下透传数据
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                // 2、同步请求头数据
                // 遍历透传请求头的数据
                String[] transparentHeaderKeys = appConfig.getSpiTransparentHeaders().split(",");
                for (String key : transparentHeaderKeys) {
                    if (!StringUtils.isEmpty(request.getHeader(key))) {
                        // 给新请求同步了老请求的cookie
                        requestTemplate.header(key, request.getHeader(key));
                    }
                }
            } else if (Objects.nonNull(currentContext)) {
                // 此处处理异步情况，attributes为null，无法获取到当前数据的上下文
                // 异步情况只设置traceId和spanId
                requestTemplate.header("X-Pix-Ywu-Span-Id", UUID.randomUUID().toString().replace("-", ""));
                requestTemplate.header("X-Pix-Ywu-Trace-Id", UUID.randomUUID().toString().replace("-", ""));
            }
        };
    }
}
